package simax.integrator.model.test;

import static org.junit.Assert.*;

import groovy.inspect.swingui.AstNodeToScriptVisitor
import org.junit.Test;

class RvMessage {
	Date   time
	String subject
	String command
	String header
	String body
	def getProperty(String name) { return attrs.get(name) }
	Map    attrs = [:]
	
	static List<RvMessage> createFrom(List<Map> messages) {
		return messages.collect { m ->
			def msg = new RvMessage(time: m.time, subject:m.subject, command:m.command, header:m.header, body:m.body)
			msg.attrs = m
			return msg
		}
	}
}

class TransitionDefinition {
	Rule rule
	List<String> eventNames = []
	
	static {
		TransitionDefinition.metaClass.의 = { rhs ->
			if (rhs instanceof Closure) {
				TransitionDefinition td = (TransitionDefinition) delegate
				Transition tr = new Transition(rule:td.rule, cond:rhs)
				eventNames.each { eventName ->
					td.rule.addTransition(eventName, tr)
				}
				return tr
			}
		}
	}
}

class Transition {
	Rule rule
	Closure cond
	State from
	State to
	NotifyEventHandler handler
	static {
		Transition.metaClass.이면 = { rhs ->
			if (delegate instanceof Transition && rhs instanceof String) {
				Transition sc = (Transition) delegate
				String from    = (String)rhs
				sc.from = sc.rule.getState(from)
				return sc
			}
		}
		
		Transition.metaClass.에서 = { rhs ->
			if (delegate instanceof Transition && rhs instanceof String) {
				Transition sc = (Transition) delegate
				String to    = (String)rhs
				sc.to = sc.rule.getState(to)
				return sc
			}
		}
		
		Transition.metaClass.로 = { rhs ->
			if (delegate instanceof Transition && rhs instanceof NotifyEventHandler ) {
				Transition sc = (Transition) delegate
				sc.handler    = (NotifyEventHandler)rhs
				return sc
			}
		}
	}
}

class State {
	String name
}

class NotifyEventHandler {
	Closure clos
	void onNotify(RvMessage m) { clos.call(m) }
}

class Context {
	List<Rule> rules = []
	
	void addRule(rule) {
		rules.add(rule)
	}
	
	void fire(RvMessage event) {
		rules.each { Rule rule -> rule.notify(event) }
	}
}

interface Rule {
	def init()
	def notify(RvMessage m)
	State getState(String name)
	State setCurrentState(String name)
	State getCurrentState()
	def addTransition(String eventName, Transition sc)
	List<Transition> getTransitions(String eventName)
}


abstract class AbstractRule implements Rule {
	abstract def init()
	AbstractRule() { init() }

	
	/** 초기 상태를 나타내는 고유한 상태 이름 */
	protected String 초기상태 = 'START'
	protected String 종료상태 = 'END'
	protected State initialState  = new State(name:초기상태)
	protected State terminalState = new State(name:종료상태)
	protected Map<String, List<Transition>> _transitionsMap = [:]
	protected Map<String, State> _stateMap = [초기상태:initialState, 종료상태:terminalState]
	protected State _currentState = initialState

	/**
	 * <code>eventName</code> 에 의해 발의되는 {@link Transition} 을 정의한다.
	 * @param eventName
	 * @return
	 */
	TransitionDefinition ㅇ(String eventName) {
		new TransitionDefinition(rule:this, eventNames:[eventName])
	}
	
	/**
	 * <code>eventNames</code>에 의해 발의되는 {@link Transition} 을 정의한다.
	 * @param eventName
	 * @return
	 */
	TransitionDefinition ㅇ(List<String> eventNames) {
		new Transition(rule:this, eventNames:eventNames)
	}

	State getCurrentState() { return _currentState }
	
	State setCurrentState(String name) {
		_currentState = getState(name)
	}
	State setCurrentState(State s) {
		_currentState = s
	}
	
	def addTransition(String eventName, Transition trans) {
		_transitionsMap.put(eventName, trans)
	}
	
	def 변경(Closure clos) {
		new NotifyEventHandler(clos:clos)
	}
	
	State getState(String name) {
		if (!_stateMap.containsKey(name))
			_stateMap.put(name, new State(name:name))
			
		_stateMap.get(name)
	}
	
	List<Transition> getTransitions(String eventName) {
		return _transitionsMap.get(eventName)
	}
	
	def notify(RvMessage m) {
		_transitionsMap[m.command].each { Transition t ->
			t.cond.resolveStrategy = Closure.DELEGATE_FIRST
			t.cond.delegate = m
			if (t.cond.call(m)) {
				t.handler.onNotify (m)
				setCurrentState(t.to)
			}
		}
	}
	
	def getTransitionGraph() {
		// 초기상태 ---[BESTWORK_REP] --> 설비할당
		// 설비할당 ---[UNLOAD] ---> 종료상태 

		/*
		 * transitionMap.each { String key, List<Transition> transitions ->
		 * 		transitions.each { Transition t ->
		 * 		    g.addEdge(t.from, t.to, [label:key])
		 *      }
		 * }
		 * 
		 */
	}
}

@Singleton
class SampleRule extends AbstractRule {
	def init() {
		ㅇ 'BESTWORK_REP' 의 { STATUS == 'PASS' } 이면 초기상태 에서 '설비할당' 로 변경 { println "설비할당상태로 전이" }
		ㅇ 'UNLOAD' 의 { STATUS == 'PASS' } 이면 '설비할당' 에서 종료상태 로 변경 { println "종료상태로 전이" }
		//ㅇ '설비할당대기' ( 'PROCESS_START' )
		//ㅇ '설비할당완료' ( )
		//ㅇ '이동지시'
		//ㅇ '이동완료'
		//ㅇ 'LOAD'
		//ㅇ 'TRACKIN'
		//ㅇ 'PROCESS'
		//ㅇ 'PROCESS완료'
		//ㅇ 'TRACKOUT'
		
		// Aspect 고려
		//ㅇ 모든상태(lot:'L1') 에서 전체메세지에 대해 { } 이면 알람('중복메세지') 발의
		//ㅇ 모든상태(lot:'L1') 에서 타임아웃 { TimeOutObserver o ->
		//	o.register('TKIN', 30)
		//	o.register('TKOUT', 15)
		//} 발생시 알람('타임아웃') 발의
	}

}

class RuleExecutorTest {

	Map<String, List<State>> stateMap	

	@Test
	public void test() {
	
		def messages = RvMessage.createFrom ([
			[command:'BESTWORK_REP', lotId:'L1', eqpId:'E1', STATUS:'PASS'],
			[command:'TKIN', lotId:'L1', eqpId:'E1'],
			[command:'TKOUT', lotId:'L1', eqpId:'E1'],			
			[command:'UNLOAD', lotId:'L1', eqpId:'E1', STATUS:'PASS'],			
		])
		
		Context context = new Context()
		context.addRule(SampleRule.instance)
		
		messages.each { RvMessage m ->			
			context.fire(m)			
		}
		
	}	

}
